#include <ed_core/tests/die.h>

#include <random>
#include <functional>

using namespace ed_core;

/*
 * class: Die
 */
quint32 Die::roll(quint32 faces)
{
  static std::random_device device;
  static std::default_random_engine engine = std::default_random_engine(device());
  std::uniform_int_distribution<quint32> dist(1,faces);

  quint32 result = 0;
  quint32 current = 0;
  do
  {
    current = dist(engine);
    result += current;
  } while (current == faces);

  return result;
}

Die::Die(quint32 faces)
  : _faces(faces)
{
}

Die::Die(const Die &other)
  : _faces(other._faces)
{
}

Die::~Die()
{
}

bool Die::operator==(const Die &other) const
{
  return _faces == other.faces();
}

Die &Die::operator=(const Die &other)
{
  _faces = other._faces;
  return *this;
}

bool Die::isValid() const
{
  return _faces > 0;
}

quint32 Die::roll() const
{
  return roll(_faces);
}

quint32 Die::faces() const
{
  return _faces;
}

/*
 * class: DicePool
 */
DicePool::DicePool(const DicePool &other)
  : _pool(other._pool),
    _baseModifier(other._baseModifier)
{
}

DicePool::DicePool(qint32 baseModifier)
  : _baseModifier(baseModifier)
{
}

DicePool::~DicePool()
{
}

DicePool &DicePool::operator=(const DicePool &other)
{
  _pool = other._pool;
  _baseModifier = other._baseModifier;
  return *this;
}

DicePool &DicePool::operator<<(const Die &p)
{
  _pool << p;
  return *this;
}

DicePool &DicePool::operator<<(const DicePool &other)
{
  _pool.append(other._pool);
  _baseModifier += other._baseModifier;
  return *this;
}

quint32 DicePool::roll(qint32 modifier)
{
  quint32 result = 0;
  foreach(const Die& d, _pool) result += d.roll();
  if (modifier < 0 && (quint32)(qAbs(modifier)) >= result) return 1; // The minimum result of a roll is always 1 (RdJ p.18)
  return result + modifier; // The modifier is added to the result of all dice rolls (RdJ p. 18)
}
